package explorandum.g6;

import java.awt.Point;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Random;

import explorandum.GameConstants;
import explorandum.Logger;
import explorandum.Move;
import explorandum.GameConstants;

public class Timer extends Thread{

	public static final int MAX_BEHAVIOR_TRANSITIONS = 3;

	private Logger log;
	private Random rand;
	private WeavingBehavior weavingBehavior;
	private CoastFollowingBehavior coastFollowingBehavior;
	private GoToUncoveredAreaBehavior goToUncoveredAreaBehavior;
	private HillClimbingBehavior hillClimbingBehavior;
	public Behavior currentBehavior;
	private Map map;
	private Point currentLocation;
	private Point[] offsets;
	private Boolean[] hasExplorer;
	private Integer[][] otherExplorers;
	private Integer[] terrain;
	private int time;
	public Move m;
	
	public Timer(Map map, Logger log, Random rand, int range, int explorers, Point currentLocation, Point[] offsets,
			Boolean[] hasExplorer, Integer[][] otherExplorers,
			Integer[] terrain, int time)
			{
		this.map = new Map();
		this.log = log;
		this.rand = rand;
		weavingBehavior = new WeavingBehavior(log, range, map);
		goToUncoveredAreaBehavior = new GoToUncoveredAreaBehavior(log, map, weavingBehavior);
		coastFollowingBehavior = new CoastFollowingBehavior(map, log, range, explorers, 250);
		hillClimbingBehavior = new HillClimbingBehavior(log, map);
		currentBehavior = coastFollowingBehavior;
		this.currentLocation = currentLocation; 
		this.offsets = offsets;
		this.hasExplorer = hasExplorer;
		this.otherExplorers = otherExplorers;
		this.terrain = terrain;
		this.time = time;
		m = new Move(GameConstants.ACTIONS[rand.nextInt(GameConstants.ACTIONS.length-1)+1]);
		setDaemon(true);
	}
	
	public Move getMove()
	{
		return m;
	}
	
	public void run()
	{
		try{
			m = realMove();
		}
		catch(Throwable error){
		//	m = new Move(GameConstants.ACTIONS[rand.nextInt(GameConstants.ACTIONS.length-1)+1]);
		}
	}
	
	public Move realMove() throws Exception {
		
		updateMap(currentLocation, offsets, hasExplorer, terrain);
		Move move = currentBehavior.move(currentLocation, offsets, hasExplorer,
				otherExplorers, terrain, time);
		
				
		// If current behavior doesn't have a move for us, pick a new behavior.
		for (int i = 0; move == null; i++) {
			// Make sure we don't infinitely loop
			if (i >= MAX_BEHAVIOR_TRANSITIONS) {
				int action = GameConstants.ACTIONS[rand.nextInt(GameConstants.ACTIONS.length)];
				log.debug("Move " + GameConstants.ACTION_NAMES[action] + " acquired from random behavior.");
				return new Move(action);
			}
			currentBehavior = getNextBehavior(currentBehavior);
			move = currentBehavior.move(currentLocation, offsets, hasExplorer,
					otherExplorers, terrain, time);
		}
		log.debug("Move " + GameConstants.ACTION_NAMES[move.getAction()] + " acquired from " + currentBehavior.getName() + " behavior.");
		return move;
	}

	public Behavior getNextBehavior(Behavior currentBehavior) {
		if (currentBehavior == coastFollowingBehavior) {
			return goToUncoveredAreaBehavior;
		} else if (currentBehavior == hillClimbingBehavior) {
			return goToUncoveredAreaBehavior;
		} else if (currentBehavior == goToUncoveredAreaBehavior) {
			return weavingBehavior;
		} else if(currentBehavior == weavingBehavior) {
			return goToUncoveredAreaBehavior;
		} else {
			assert false : "Invalid input to getNextBehavior";
			return weavingBehavior;
		}
	}
	
	public void updateMap(Point currentLocation, Point[] offsets,
			Boolean[] hasExplorer, Integer[] terrain) {
		for (int i = 0; i < offsets.length; i++) {
			Cell cell = new Cell(terrain[i], hasExplorer[i]);
			map.set(offsets[i].x, offsets[i].y, cell);
		}

		//log.debug("map:\n" + map.toString());
	}

	
}
